/* 
 * File:   scanner.cpp
 * Author: alexey
 * 
 * Created on 30 Март 2011 г., 20:31
 */

#include "scanner.h"
#include <fcntl.h>
#include <iostream>
#include "../md5/md5.h"

using namespace storagemon;
using namespace boost::filesystem;

Scanner::Scanner(IStorage* storage, IServiceLocator* sl)
: m_storage(storage), m_sl(sl), m_id(0), m_fileId(0), m_tracer(0)
{
    m_storageFactory = static_cast<IStorageServiceFactory*>(m_sl->GetService(STORAGE_FACTORY));
    try
    {
        m_tracer = static_cast<ITracer*>(m_sl->GetService(TRACER_SERVICE));
    }
    catch(std::runtime_error &e)
    {
        
    }
    if (m_tracer)
        m_tracer->Write("Scanner::Scanner...", TraceLavelDebug);
}

Scanner::~Scanner()
{
}

bool Scanner::Tree()
{
    path p(m_storage->path());
    if (!is_directory(p))
        return false;
    return ScanDirectoryTree(p.directory_string().c_str(), 0);
}

bool Scanner::Scan()
{
    if (!m_storage->size())
        return false;

    int size = m_storage->size();

    for (int i = 0 ; i != size; i++)
    {
        ScanDirectory(m_storage->get_dir(i));
    }
    return true;
}

bool Scanner::ScanDirectoryTree(const char* dir, u_long parent_id, bool rec)
{
    path p(dir);
    if (!is_directory(p))
        return false;

    std::vector<path> folder;


    copy(directory_iterator(p), directory_iterator(), back_inserter(folder));

    sort(folder.begin(), folder.end());
    IDirectory *dirObj =
            static_cast<IDirectory*>(m_storageFactory->CreateService(DIRECTORYOBJECT,
            p.filename().c_str(),
            p.directory_string().c_str(), m_id, parent_id, 0));
    m_storage->add_dir(dirObj);
    parent_id = m_id;
    m_id++;
    std::vector<path>::const_iterator it;
    for (it = folder.begin(); it != folder.end(); ++it)
    {
        ScanDirectoryTree(it->directory_string().c_str(), parent_id);
    }
    return true;
}

bool Scanner::ScanDirectory(std::vector<IDirectory*>::iterator dir)
{
    path p((*dir)->path());
    if (!is_directory(p))
        return false;

    std::vector<path> folder_content;

    copy(directory_iterator(p), directory_iterator(), back_inserter(folder_content));
    sort(folder_content.begin(), folder_content.end());

    std::vector<path>::const_iterator it;
    for (it = folder_content.begin(); it != folder_content.end(); ++it)
    {
        if (is_regular_file(*it))
        {
            IFile* f = ScanFile(*it, (*dir)->id());
            (*dir)->add_file(f);

            char md5[MD5_BLOCK_SIZE];
            std::cout << "file:"<< f->full_path()
                    << "\nmd5= " << f->md5_string(md5) << "\n";
        }
    }
}

IFile* Scanner::ScanFile(path file, u_long parent_id)
{
    char buf[MD5_DIGEST_SIZE];
    FILE* f = fopen(file.string().c_str(), "r");
    utils::md5_stream(f, buf);
    fclose(f);
    return static_cast<IFile*>(m_storageFactory->CreateService(FILEOBJECT,
            file.parent_path().string().c_str(),
            file.filename().c_str(), m_fileId++, parent_id, buf));
}


